package com.example.dictionary.util;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.util.Pool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * Kryo 序列化工具类
 * 使用 KryoPool 提高性能
 */
public class KryoSerializer {
    
    private static final Logger log = LoggerFactory.getLogger(KryoSerializer.class);
    
    // Kryo Pool 工厂
    private static final Pool<Kryo> pool = new Pool<Kryo>(true, false, 8) {
        @Override
        protected Kryo create() {
            Kryo kryo = new Kryo();
            // 注册常用类，提高序列化效率
            kryo.register(java.util.ArrayList.class);
            kryo.register(java.util.HashMap.class);
            kryo.register(java.util.LinkedHashMap.class);
            kryo.register(java.time.LocalDateTime.class);
            // 设置引用为 false，提高性能（但会占用更多空间）
            kryo.setReferences(false);
            // 启用注册（提高性能，但需要注册所有类）
            kryo.setRegistrationRequired(false);
            return kryo;
        }
    };
    
    /**
     * 序列化对象为字节数组
     * 
     * @param obj 要序列化的对象
     * @return 序列化后的字节数组
     */
    public static byte[] serialize(Object obj) {
        if (obj == null) {
            return null;
        }
        
        Kryo kryo = pool.obtain();
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            // 使用合适的初始缓冲区大小，避免频繁扩容
            try (Output output = new Output(baos, 4096)) {
                kryo.writeClassAndObject(output, obj);
                output.flush();
            }
            byte[] result = baos.toByteArray();
            // log.debug("序列化对象: {} -> {} bytes", obj.getClass().getSimpleName(), result.length);
            return result;
        } catch (Exception e) {
            log.error("序列化对象失败: {}", obj.getClass().getName(), e);
            throw new RuntimeException("序列化失败: " + e.getMessage(), e);
        } finally {
            pool.free(kryo);
        }
    }
    
    /**
     * 反序列化字节数组为对象
     * 
     * @param data 序列化的字节数组
     * @return 反序列化后的对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T deserialize(byte[] data) {
        if (data == null || data.length == 0) {
            return null;
        }
        
        Kryo kryo = pool.obtain();
        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(data);
            // 使用合适的缓冲区大小
            try (Input input = new Input(bais, data.length)) {
                Object obj = kryo.readClassAndObject(input);
                return (T) obj;
            }
        } catch (Exception e) {
            log.error("反序列化对象失败 (数据长度: {} bytes)", data.length, e);
            // 记录数据的前几个字节用于调试
            int previewLen = Math.min(20, data.length);
            StringBuilder hexPreview = new StringBuilder();
            for (int i = 0; i < previewLen; i++) {
                hexPreview.append(String.format("%02x ", data[i]));
            }
            log.error("数据预览 (前{}字节): {}", previewLen, hexPreview);
            throw new RuntimeException("反序列化失败: " + e.getMessage(), e);
        } finally {
            pool.free(kryo);
        }
    }
    
    /**
     * 反序列化字节数组为指定类型的对象
     * 
     * @param data 序列化的字节数组
     * @param clazz 目标类型
     * @return 反序列化后的对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T deserialize(byte[] data, Class<T> clazz) {
        if (data == null || data.length == 0) {
            return null;
        }
        
        Kryo kryo = pool.obtain();
        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(data);
            // 使用合适的缓冲区大小，确保能读取所有数据
            try (Input input = new Input(bais, data.length)) {
                // 使用 readClassAndObject 来匹配 serialize 方法的 writeClassAndObject
                Object obj = kryo.readClassAndObject(input);
                if (obj != null && clazz.isInstance(obj)) {
                    return (T) obj;
                } else if (obj != null) {
                    log.warn("反序列化对象类型不匹配: 期望 {}, 实际 {}", clazz.getName(), obj.getClass().getName());
                    return null;
                }
                return null;
            }
        } catch (Exception e) {
            log.error("反序列化对象失败: {} (数据长度: {} bytes)", clazz.getName(), data != null ? data.length : 0, e);
            // 记录数据的前几个字节用于调试
            if (data != null && data.length > 0) {
                int previewLen = Math.min(20, data.length);
                StringBuilder hexPreview = new StringBuilder();
                for (int i = 0; i < previewLen; i++) {
                    hexPreview.append(String.format("%02x ", data[i]));
                }
                log.error("数据预览 (前{}字节): {}", previewLen, hexPreview);
            }
            throw new RuntimeException("反序列化失败: " + e.getMessage(), e);
        } finally {
            pool.free(kryo);
        }
    }
}

